package com.xjscrm.console.service.customer.chat.impl;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.xjscrm.common.annotation.MerId;
import com.xjscrm.common.entity.*;
import com.xjscrm.console.chat.cache.CacheHolder;
import com.xjscrm.console.chat.frame.dto.ChatRecordDTO;
import com.xjscrm.console.chat.frame.dto.ChatSessionDTO;
import com.xjscrm.console.chat.frame.recv.RPullSessionMsg;
import com.xjscrm.console.chat.frame.recv.RPullTalkSessionMsg;
import com.xjscrm.console.chat.frame.send.SConversationCleanMsg;
import com.xjscrm.console.chat.frame.send.SConversationExpireMsg;
import com.xjscrm.console.chat.frame.send.SConversationExpiredMsg;
import com.xjscrm.console.chat.queue.ChatDelayProducer;
import com.xjscrm.console.chat.queue.ChatDelayTask;
import com.xjscrm.console.chat.utils.MessageUtil;
import com.xjscrm.console.dto.chat.ChatTalkSessionQueryDTO;
import com.xjscrm.console.dto.chat.setting.ChatAutoReplyJsonDTO;
import com.xjscrm.console.dto.chat.setting.ChatDialogRuleJsonDTO;
import com.xjscrm.console.entity.ChatTalkRecord;
import com.xjscrm.console.entity.ChatTalkSession;
import com.xjscrm.console.mapper.*;
import com.xjscrm.console.mq.producer.SendMsgProducer;
import com.xjscrm.console.service.customer.chat.ChatDispatchSettingsService;
import com.xjscrm.console.service.customer.chat.ChatTalkRecordService;
import com.xjscrm.console.service.customer.chat.ChatTalkSessionService;
import com.xjscrm.console.service.customer.chat.ChatTalkSessionStaffRelService;
import com.xjscrm.console.service.customer.group.WwGroupService;
import com.xjscrm.console.service.customer.wwCustomer.WwCustomerService;
import com.xjscrm.console.service.customer.wwDevice.WwDeviceService;
import com.xjscrm.console.vo.LoginVO;
import com.xjscrm.console.vo.chat.ChatDispatchSettingsVO;
import com.xjscrm.console.vo.chat.ChatTalkSessionDeviceVO;
import com.xjscrm.console.vo.chat.ChatTalkSessionVO;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 聊天回话(ChatTalkSession)表服务实现类
 *
 * @author szl
 * @since 2024-03-12 13:35:17
 */
@Service
@Slf4j
public class ChatTalkSessionServiceImpl implements ChatTalkSessionService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    @Autowired
    private ChatTalkSessionMapper chatTalkSessionMapper;
    @Autowired
    private ChatTalkRecordMapper chatTalkRecordMapper;
    @Autowired
    private ChatTalkRecordService chatTalkRecordService;
    @Autowired
    private ChatTalkSessionStaffRelService chatTalkSessionStaffRelService;
    @Autowired
    private WwDeviceService wwDeviceService;
    @Autowired
    private ChatDispatchSettingsService chatDispatchSettingsService;
    @Autowired
    private SendMsgProducer sendMsgProducer;
    @Autowired
    private CacheHolder cacheHolder;
    @Autowired
    private ChatTalkSessionStaffRelService talkSessionStaffRelService;
    @Autowired
    private WwCustomerService wwCustomerService;
    @Autowired
    private WwCustomerTagsMapper wwCustomerTagsMapper;
    @Autowired
    private WwGroupTagsRelationMapper wwGroupTagsRelationMapper;
    @Autowired
    private WwTagsMapper wwTagsMapper;
    @Autowired
    private WwGroupTagMapper wwGroupTagMapper;
    @Autowired
    private WwGroupService wwGroupService;


    @Override
    public List<ChatTalkSession> loadByDeviceUniqueId(RPullTalkSessionMsg content) {
        // todo 添加缓存优化

        List<ChatTalkSession> list = this.chatTalkSessionMapper.selectByDeviceUniqueId(content.getMerId(), content.getDeviceUniqueId());

        return list;
    }

    @Override
    public ChatSessionDTO get(ChatTalkSessionQueryDTO query) {
        // todo 添加缓存优化

        ChatTalkSession one = this.chatTalkSessionMapper.select(query);
        if (Objects.isNull(one)) {
            return null;
        }
        ChatSessionDTO chatSessionDTO = new ChatSessionDTO();
        BeanUtils.copyProperties(one, chatSessionDTO);
        return chatSessionDTO;
    }

    @Override
    public void add(ChatTalkSession talkSession) {
        if (this.chatTalkSessionMapper.existsByConversationName(talkSession.getMerId(), talkSession.getDeviceUniqueId(), talkSession.getConversationId()) <= 0) {
            this.chatTalkSessionMapper.insertSelective(talkSession);
        }
        //todo  添加缓存更新
    }

    @Override
    public void update(ChatTalkSession newTalkSession) {
        this.chatTalkSessionMapper.updateByPrimaryKeySelective(newTalkSession);
    }

    @Override
    public void delete(@MerId Long merId, Long id) {
        this.chatTalkSessionMapper.deleteByPrimaryKey(id);
    }

    @Override
    public ChatTalkSession getById(@MerId Long merId, Long talkSessionId) {

        return chatTalkSessionMapper.selectByPrimaryKey(talkSessionId);
    }

    @Override
    public Object search(LoginVO login, ChatTalkSessionQueryDTO query) {

        Page<ChatTalkSession> page = new Page<>(query.getCurrent(), query.getSize());
        // 查询
        List<ChatTalkSession> chatShieldTalkSession = chatTalkSessionMapper.page(page, query);

        if (ObjectUtils.isEmpty(chatShieldTalkSession)) {
            return new Page<>(query.getCurrent(), query.getSize());
        }
        List<ChatTalkSessionVO> records = new ArrayList<>();
        for (ChatTalkSession talkSession : chatShieldTalkSession) {
            ChatTalkSessionVO chatTalkSession = new ChatTalkSessionVO();
            BeanUtils.copyProperties(talkSession, chatTalkSession);
            if (Objects.equals(talkSession.getType(), 110)) {
                WwCustomer customer = wwCustomerService.getByWxId(login.getMerId(), talkSession.getDeviceUniqueId(), talkSession.getConversationId());
                if (Objects.nonNull(customer)) {
                    chatTalkSession.setConversationAvatar(customer.getHeadImgUrl());
                }
            } else {
                WwGroup byGroupId = wwGroupService.getByGroupId(login.getMerId(), talkSession.getDeviceUniqueId(), talkSession.getConversationId());
                if (Objects.nonNull(byGroupId)) {
                    chatTalkSession.setConversationAvatar(byGroupId.getHeadImageUrl());
                }
            }
            records.add(chatTalkSession);
        }

        Page<ChatTalkSessionVO> result = new Page<>(page.getCurrent(), page.getSize());
        result.setTotal(page.getTotal());
        result.setRecords(records);
        return result;
    }

    @Override
    public List<ChatTalkSessionDeviceVO> listDevice(LoginVO login) {

        boolean isMaster = Objects.equals(login.getId(), login.getMerId());

        List<ChatTalkSessionDeviceVO> shieldDeviceList = chatTalkSessionMapper.selectShieldCountWithDeviceUniqueId(login.getMerId());
        if (ObjectUtils.isEmpty(shieldDeviceList)) {
            return Lists.newArrayList();
        }

        for (ChatTalkSessionDeviceVO chatTalkSessionDeviceVO : shieldDeviceList) {
            WwDevice byId = wwDeviceService.getById(login.getMerId(), chatTalkSessionDeviceVO.getDeviceUniqueId());
            if (Objects.isNull(byId)) {
                continue;
            }
            chatTalkSessionDeviceVO.setDeviceName(byId.getDeviceName());
            chatTalkSessionDeviceVO.setHeadImgUrl(byId.getHeadImgUrl());
        }
        return shieldDeviceList;
    }

    @Override
    @Transactional
    public Boolean removeShield(LoginVO login, List<Long> ids) {

        List<ChatTalkSession> chatTalkSessions = chatTalkSessionMapper.selectByIds(login.getMerId(), ids);

        for (ChatTalkSession chatTalkSession : chatTalkSessions) {
            ChatTalkSession update = new ChatTalkSession();
            update.setId(chatTalkSession.getId());
            update.setOpenShield(0);
            update.setUpdateTime((int) (System.currentTimeMillis() / 1000L));

            chatTalkSessionMapper.updateByPrimaryKeySelective(update);
        }
        return true;
    }

    @Override
    public Boolean syncShield(LoginVO login, List<Long> ids, List<Long> deviceUniqueIds) {

        List<ChatTalkSession> chatTalkSessions = chatTalkSessionMapper.selectByIds(login.getMerId(), ids);

        for (ChatTalkSession chatTalkSession : chatTalkSessions) {
            deviceUniqueIds.remove(chatTalkSession.getDeviceUniqueId());

            if (ObjectUtils.isEmpty(deviceUniqueIds)) {
                return true;
            }
            for (Long deviceUniqueId : deviceUniqueIds) {
                ChatTalkSession chatTalkSession1 = chatTalkSessionMapper.selectByConversationId(login.getMerId(), chatTalkSession.getConversationId(), deviceUniqueId);
                if (Objects.nonNull(chatTalkSession1)) {
                    chatTalkSession1.setOpenShield(1);
                    chatTalkSession1.setOpenShieldTime((int) (System.currentTimeMillis() / 1000L));
                    chatTalkSessionMapper.updateByPrimaryKeySelective(chatTalkSession1);
                    continue;
                }
                ChatTalkSession newTalkSession = new ChatTalkSession();
                newTalkSession.setId(IdUtil.getSnowflakeNextId());
                newTalkSession.setMerId(chatTalkSession.getMerId());
                newTalkSession.setDeviceUniqueId(deviceUniqueId);
                newTalkSession.setDeviceId(chatTalkSession.getDeviceId());
                newTalkSession.setDeviceType(chatTalkSession.getDeviceType());
                newTalkSession.setConversationId(chatTalkSession.getConversationId());
                newTalkSession.setConversationName(chatTalkSession.getConversationName());
                newTalkSession.setType(chatTalkSession.getType());
                newTalkSession.setOpenShield(1);
                newTalkSession.setOpenShieldTime((int) (System.currentTimeMillis() / 1000L));
                newTalkSession.setCreateTime((int) (System.currentTimeMillis() / 1000L));
                newTalkSession.setUpdateTime((int) (System.currentTimeMillis() / 1000L));
                chatTalkSessionMapper.insertSelective(newTalkSession);
            }
        }
        return true;
    }

    @Override
    public ChatTalkSession getByConversationIdAndDeviceId(@MerId Long merId, String conversationId, String deviceId) {
        return chatTalkSessionMapper.selectByConversationIdAndDeviceId(merId, conversationId, deviceId);
    }

    @Override
    public ChatTalkSession getByConvIdAndDeviceUniqueId(@MerId Long merId, Long deviceUniqueId, String conversationId) {
        return chatTalkSessionMapper.selectByConversationId(merId, conversationId, deviceUniqueId);
    }

    @Override
    public List<ChatTalkSession> getByIds(@MerId Long merId, List<Long> newTalkSessionIds) {
        return chatTalkSessionMapper.selectByIds(merId, newTalkSessionIds);
    }

    @Override
    public void fillTag(ChatTalkSession talkSession, Consumer<WwTags> callback, Consumer<WwGroupTags> ca) {
        Long merId = talkSession.getMerId();

        List<Long> tagIds = null;

        if (Objects.equals(talkSession.getType(), 110)) {
            WwCustomer customer = wwCustomerService.getByWxId(merId, talkSession.getDeviceUniqueId(), talkSession.getConversationId());
            if (Objects.nonNull(customer)) {
                //
                List<WwCustomerTags> relTags = wwCustomerTagsMapper.selectListByCustomerId(merId, customer.getId());
                if (ObjectUtils.isNotEmpty(relTags)) {
                    tagIds = relTags.stream().map(WwCustomerTags::getTagId).distinct().collect(Collectors.toList());
                }
                if (ObjectUtils.isEmpty(tagIds)) {
                    return;
                }
                List<WwTags> tags = wwTagsMapper.selectListByIds(merId, tagIds);
                if (ObjectUtils.isNotEmpty(tags)) {
                    for (WwTags tag : tags) {
                        callback.accept(tag);
                    }
                }
            }
        } else {
            List<WwGroupTagsRelation> relTags = wwGroupTagsRelationMapper.selectListByGroupId(merId, talkSession.getDeviceId(), talkSession.getConversationId());
            if (ObjectUtils.isNotEmpty(relTags)) {
                tagIds = relTags.stream().map(WwGroupTagsRelation::getTagId).distinct().collect(Collectors.toList());
            }
            if (ObjectUtils.isEmpty(tagIds)) {
                return;
            }
            List<WwGroupTags> tags = wwGroupTagMapper.selectListByIds(merId, tagIds);
            if (ObjectUtils.isNotEmpty(tags)) {
                for (WwGroupTags tag : tags) {
                    ca.accept(tag);
                }
            }
        }
    }

    @Override
    public void fillConversationName(ChatTalkSession talkSession, ChatSessionDTO talkSessionMsg) {
        Long merId = talkSession.getMerId();
        if (Objects.equals(talkSession.getType(), 110)) {
            WwCustomer customer = wwCustomerService.getByWxId(merId, talkSession.getDeviceUniqueId(), talkSession.getConversationId());
            if (Objects.nonNull(customer)) {
                talkSessionMsg.setRelId(customer.getId());
                talkSessionMsg.setConversationName(StringUtils.defaultIfBlank(customer.getRemark(), customer.getName()));
                talkSessionMsg.setConversationAvatar(customer.getHeadImgUrl());
            }
        } else {
            WwGroup byGroupId = wwGroupService.getByGroupId(merId, talkSession.getDeviceUniqueId(), talkSession.getConversationId());
            if (Objects.nonNull(byGroupId)) {
                talkSessionMsg.setRelId(byGroupId.getId());
                talkSessionMsg.setConversationName(byGroupId.getGroupName());
            }
        }
    }

    @Override
    public List<ChatTalkSession> listByConversationIds(@MerId Long merId, Long deviceUniqueId, List<String> conversationIds) {
        List<ChatTalkSession> sessionList = chatTalkSessionMapper.selectListByConversationIds(merId, deviceUniqueId, conversationIds);
        if (ObjectUtils.isEmpty(sessionList)) {
            return Lists.newArrayList();
        }
        return sessionList;
    }

    @Override
    public boolean checkConversationName(@MerId Long merId, Long deviceUniqueId, String conversationName) {
        return chatTalkSessionMapper.selectExistsByName(merId, deviceUniqueId, conversationName) > 0;
    }

    @Override
    public List<Long> listOrderSessionIds(@MerId Long merId, Long staffId, Long deviceUniqueId) {
        return chatTalkSessionMapper.selectListIdsWithOrderSessionExcludeId(merId, staffId, deviceUniqueId);
    }

    @Override
    public ChatSessionDTO convert(ChatTalkSession talkSession) {
        ChatSessionDTO talkSessionMsg = new ChatSessionDTO();
        BeanUtils.copyProperties(talkSession, talkSessionMsg);
        this.fillTag(talkSession, tag -> {
            if (Objects.equals(tag.getType(), 1)) {
                talkSessionMsg.getCompanyTagIds().add(tag.getId());
            } else if (Objects.equals(tag.getType(), 1)) {
                talkSessionMsg.getSelfTagIds().add(tag.getId());
            }
        }, tag1 -> {
            talkSessionMsg.getSelfTagIds().add(tag1.getId());
        });

        this.fillConversationName(talkSession, talkSessionMsg);
        ChatTalkRecord chatTalkRecord = chatTalkRecordService.getById(talkSession.getMerId(), talkSession.getLastRecvId());
        ChatRecordDTO chatRecordDTO = new ChatRecordDTO();
        if (Objects.nonNull(chatTalkRecord)) {
            BeanUtils.copyProperties(chatTalkRecord, chatRecordDTO);
            chatRecordDTO.parse();
        }
        talkSessionMsg.setLastTalkRecord(chatRecordDTO);
        return talkSessionMsg;
    }

    @Override
    public void fetchAndPushOrderSession(Long merId, Long staffId, Long deviceUniqueId, Long... excludeSessionId) {

        Integer tempSessionNowCount = talkSessionStaffRelService.countByStaffId(merId, staffId);
        //
        Integer tempSessionCount = cacheHolder.getStaffSessionCount(merId, staffId);
        //
        int fetchCount = tempSessionCount - tempSessionNowCount;
        if (fetchCount <= 0) {
            return;
        }

        List<Long> orderSessionIds = cacheHolder.getSessionOrder(merId, deviceUniqueId, fetchCount);
        //
        if (ObjectUtils.isEmpty(orderSessionIds)) {
            orderSessionIds = cacheHolder.getSessionLeave(merId, deviceUniqueId, fetchCount);
            if (ObjectUtils.isEmpty(orderSessionIds)) {
                return;
            }
        }
        if (ArrayUtil.isNotEmpty(excludeSessionId)) {
            for (Long l : excludeSessionId) {
                orderSessionIds.remove(l);
            }
        }
        if (ObjectUtils.isNotEmpty(orderSessionIds)) {

            for (Long orderSessionId : orderSessionIds) {
                // 删除排队和留言的缓存
                cacheHolder.delSessionOrder(merId, deviceUniqueId, orderSessionId);
                cacheHolder.delSessionLeave(merId, deviceUniqueId, orderSessionId);
                cacheHolder.delSessionOrderRepeatTime(deviceUniqueId, orderSessionId);
                ChatTalkSession byId = this.getById(merId, orderSessionId);
                //
                ChatSessionDTO d = this.convert(byId);
                Channel staffChannel = cacheHolder.getStaffChannel(staffId);
                //
                talkSessionStaffRelService.addIfAbsent(merId, byId, staffId);
                this.addChatSendDelayTask(merId, staffId, byId);
                MessageUtil.sendNewSessionTalk(staffChannel, d, d.getLastTalkRecord());
            }
        }
    }

    // 延迟任务相关的方法

    @Override
    public Page<ChatTalkSession> page(@MerId Long merId, RPullSessionMsg content) {

        Page<ChatTalkSession> page = new Page<>(content.getCurrent(), content.getSize());

        ChatTalkSessionQueryDTO query = new ChatTalkSessionQueryDTO();
        query.setMerId(merId);
        query.setDeviceUniqueId(content.getDeviceUniqueId());
        query.setConversationName(content.getSearchContent());
        query.setIds(content.getSessionIds());
        query.setStartTime(content.getStartTime());
        query.setEndTime(content.getEndTime());
        query.setType(content.getType());

        List<ChatTalkSession> records = chatTalkSessionMapper.page(page, query);

        page.setRecords(records);
        return page;
    }

    /**
     *
     */
    @Override
    public void addChatRecvDelayTask(@MerId Long merId, Long staffId, ChatTalkSession talkSession) {
        //
        this.delChatRecvDelayTask(merId, staffId, talkSession);
        //
        ChatDispatchSettingsVO dispatchSettings = chatDispatchSettingsService.get(merId);
        //
        ChatDialogRuleJsonDTO dialogRuleConf = dispatchSettings.getDialogRuleConf();
        if (Objects.equals(dialogRuleConf.getOpenEnd(), 0)) {
            log.info("未打开自动结束开关, ik");
            return;
        }
        Integer endTimeout = dialogRuleConf.getEndTimeout();
        if (Objects.isNull(endTimeout) || endTimeout <= 0) {
            log.info("配置的客户回复超时时间错误: {}", endTimeout);
            return;
        }
        //
        this.delChatSendDelayTask(merId, staffId, talkSession);
        // 添加任务
        ChatDelayTask delayTask = new ChatDelayTask(merId, staffId, talkSession.getId(),
                //
                endTimeout * 60L,
                //
                () -> this.endTalkSession(merId, staffId, talkSession.getId(), true));
        ChatDelayProducer.instance.addRecvDelayTask(delayTask);
    }

    @Override
    public void delChatRecvDelayTask(@MerId Long merId, Long staffId, ChatTalkSession talkSession) {
        ChatDelayTask delayTask = new ChatDelayTask(merId, staffId, talkSession.getId(), -1L, () -> {
        });
        ChatDelayProducer.instance.removeRecvTask(delayTask);
    }

    @Override
    public void addChatSendDelayTask(@MerId Long merId, Long staffId, ChatTalkSession talkSession) {
        ChatDispatchSettingsVO dispatchSettings = chatDispatchSettingsService.get(merId);
        //
        ChatDialogRuleJsonDTO dialogRuleConf = dispatchSettings.getDialogRuleConf();
        if (Objects.equals(dialogRuleConf.getOpenTimeout(), 0)) {
            log.error("未打开客服回复超时, 超时处理将被忽略.");
            return;
        }
        Integer replyTimeout = dialogRuleConf.getReplyTimeout();
        if (Objects.isNull(replyTimeout) || replyTimeout <= 0) {
            log.info("配置的客服回复超时时间错误: {}", replyTimeout);
            return;
        }
        Integer sessionTimeout = dialogRuleConf.getSessionTimeout();
        if (Objects.isNull(sessionTimeout) || sessionTimeout <= 0) {
            log.info("配置的客服回复超时倒计时时间错误: {}", sessionTimeout);
            return;
        }
        long current = System.currentTimeMillis() / 1000L;
        chatTalkSessionStaffRelService.updateExpireTime(merId, talkSession, current, current + sessionTimeout * 60L);

        Channel staffChannel = cacheHolder.getStaffChannel(staffId);
        if (Objects.nonNull(staffChannel)) {
            SConversationExpireMsg expireMsg = new SConversationExpireMsg();
            expireMsg.setTalkSessionId(talkSession.getId());
            expireMsg.setDeviceUniqueId(talkSession.getDeviceUniqueId());
            expireMsg.setExpireTime(current + replyTimeout * 60L);
            expireMsg.setShowExpireTime(current + sessionTimeout * 60L);
            staffChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(expireMsg)));
        }
        //
        this.delChatRecvDelayTask(merId, staffId, talkSession);
        //
        this.delChatSendDelayTask(merId, staffId, talkSession);
        // 添加任务
        ChatDelayTask chatSendDelayTask = new ChatDelayTask(merId, staffId, talkSession.getId(),
                //
                replyTimeout * 60L,
                //
                () -> this.markTalkSessionTimeout(merId, staffId, talkSession.getId()));
        ChatDelayProducer.instance.addSendDelayTask(chatSendDelayTask);
    }

    @Override
    public void delChatSendDelayTask(@MerId Long merId, Long staffId, ChatTalkSession talkSession) {
        ChatDelayTask chatSendDelayTask = new ChatDelayTask(merId, staffId, talkSession.getId(), -1L, () -> {
        });
        ChatDelayProducer.instance.removeSendTask(chatSendDelayTask);
    }

    @Override
    @Deprecated
    public void addChatCleanDelayTask(@MerId Long merId, Long staffId, ChatTalkSession talkSession) {
        //
        this.delChatCleanDelayTask(merId, staffId, talkSession);
        //
        ChatDispatchSettingsVO dispatchSettings = chatDispatchSettingsService.get(merId);
        //
        ChatDialogRuleJsonDTO dialogRuleConf = dispatchSettings.getDialogRuleConf();

        Integer cleanTimeout = dialogRuleConf.getCleanTimeout();
        if (Objects.isNull(cleanTimeout) || cleanTimeout <= 0) {
            log.info("添加清除会话延迟任务被忽略, 客户配置的清理时间长度错误");
            return;
        }
        // 添加任务
        ChatDelayTask chatSendDelayTask = new ChatDelayTask(merId, staffId, talkSession.getId(), cleanTimeout * 60L, () -> this.cleanTalkSession(merId, staffId, talkSession.getId()));
        ChatDelayProducer.instance.addCleanDelayTask(chatSendDelayTask);
    }

    @Override
    public void delChatCleanDelayTask(@MerId Long merId, Long staffId, ChatTalkSession talkSession) {
        ChatDelayTask cleanDelayTask = new ChatDelayTask(merId, staffId, talkSession.getId(), -1L, () -> {
        });
        ChatDelayProducer.instance.removeCleanTask(cleanDelayTask);
    }

    @Override
    public void endTalkSession(@MerId Long merId, Long staffId, Long talkSessionId, Boolean auto) {

        log.info("执行结束会话操作, merId: {}, staffId: {}, talkSessionId: {}, auto: {}", merId, staffId, talkSessionId, auto);

        ChatTalkSession talkSession = chatTalkSessionMapper.selectByPrimaryKey(talkSessionId);
        if (Objects.isNull(talkSession)) {
            log.error("会话未找到, 结束会话回复失败");
            return;
        }
        //
        chatTalkSessionStaffRelService.markSessionRelEnd(merId, staffId, talkSession.getDeviceUniqueId(), talkSession.getId());
        //
        Channel staffChannel = cacheHolder.getStaffChannel(staffId);
        //
        if (Objects.nonNull(staffChannel)) {
            /*log.error("发送前端会话结束通知失败, 员工未在线!");
            return;*/
            //
//            SConversationEndMsg conversationEndMsg = new SConversationEndMsg();
            SConversationCleanMsg conversationEndMsg = new SConversationCleanMsg();
            conversationEndMsg.setTalkSessionId(String.valueOf(talkSessionId));
            conversationEndMsg.setDeviceUniqueId(talkSession.getDeviceUniqueId());
            staffChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(conversationEndMsg)));
        }
        //
        // this.addChatCleanDelayTask(merId, staffId, talkSession);
        // 清理
        chatTalkSessionStaffRelService.delSessionRel(merId, staffId, talkSession.getDeviceUniqueId(), talkSessionId);
        // 结束
        ChatDispatchSettingsVO dispatchSettings = chatDispatchSettingsService.get(merId);
        //
        ChatAutoReplyJsonDTO autoReplyConf = dispatchSettings.getAutoReplyConf();

        if (Objects.equals(autoReplyConf.getOpenEndReply(), 0)) {
            log.error("分发设置未开启结束对话设置");
            return;
        }

        String replyText = auto ? autoReplyConf.getEndReplyAutoText() : autoReplyConf.getEndReplyManualText();
        if (StringUtils.isBlank(replyText)) {
            log.error("分发设置未配置结束回复语");
            return;
        }
        //
        ChatTalkRecord replyRecord = chatTalkRecordService.buildTextRecord(merId, staffId, talkSession, replyText);

        sendMsgProducer.replySessionText(talkSession, replyRecord);
        //
        /*ChatEvaluateJsonDTO evaluateConf = dispatchSettings.getEvaluateConf();
        if (Objects.equals(evaluateConf.getOpenEvaluate(), 0)) {
            log.error("分发设置未开启客服评价");
            return;
        }
        String evaluateText = evaluateConf.getEvaluateText();
        if (StringUtils.isBlank(evaluateText)) {
            log.error("分发设置中客户评价话术为空, 忽略");
            return;
        }
        //
        ChatTalkRecord evaluateRecord = buildTextRecord(merId, staffId, talkSession, evaluateText);
        chatTalkRecordMapper.insertSelective(evaluateRecord);
        //
        this.replySessionText(talkSession, evaluateRecord);*/
    }

    @Override
    @Deprecated
    public void cleanTalkSession(@MerId Long merId, Long staffId, Long talkSessionId) {

        ChatTalkSession talkSession = chatTalkSessionMapper.selectByPrimaryKey(talkSessionId);
        if (Objects.isNull(talkSession)) {
            log.error("会话未找到, 清理会话失败");
            return;
        }
        chatTalkSessionStaffRelService.delFromConversationClean(merId, staffId, talkSession.getDeviceUniqueId(), talkSession.getId());

        Channel staffChannel = cacheHolder.getStaffChannel(staffId);
        if (Objects.nonNull(staffChannel)) {
            SConversationCleanMsg cleanMsg = new SConversationCleanMsg();
            cleanMsg.setTalkSessionId(String.valueOf(talkSessionId));
            cleanMsg.setDeviceUniqueId(talkSession.getDeviceUniqueId());
            staffChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(cleanMsg)));
        }
    }

    @Override
    public void markTalkSessionTimeout(@MerId Long merId, Long staffId, Long talkSessionId) {

        ChatTalkSession talkSession = chatTalkSessionMapper.selectByPrimaryKey(talkSessionId);
        if (Objects.isNull(talkSession)) {
            log.error("会话未找到, 标记会话超时失败");
            return;
        }
        chatTalkSessionStaffRelService.markSessionRelExpire(merId, staffId, talkSession.getDeviceUniqueId(), talkSession.getId());

        Channel staffChannel = cacheHolder.getStaffChannel(staffId);
        if (Objects.nonNull(staffChannel)) {
            SConversationExpiredMsg expiredMsg = new SConversationExpiredMsg();
            expiredMsg.setTalkSessionId(talkSessionId);
            expiredMsg.setDeviceUniqueId(talkSession.getDeviceUniqueId());
            staffChannel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(expiredMsg)));
        }
    }

    @Override
    public List<ChatTalkSession> listByIds(@MerId Long merId, List<Long> talkSessionIds) {
        return chatTalkSessionMapper.selectByIds(merId, talkSessionIds);
    }
}

